/******************************************************************************
 * SAGE - Scalable Adaptive Graphics Environment
 *
 * Module: sail.h
 * Author : Byungil Jeong
 *
 * Copyright (C) 2004 Electronic Visualization Laboratory,
 * University of Illinois at Chicago
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either Version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License along
 * with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Direct questions, comments etc about SAGE to bijeong@evl.uic.edu or 
 * http://www.evl.uic.edu/cavern/forum/
 *
 *****************************************************************************/

#ifndef SAIL_H_
#define SAIL_H_

#include "sage.h"
#include "sageSync.h"
#include "streamProtocol.h"
#include "sageTcpModule.h"
#include "sageUdpModule.h"

#ifdef SAGE_AUDIO
#include "sageAudioModule.h"
#include "audioCircBuf.h"
#endif

#include <deque>

#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#if defined(SAGE_GPU)

#include "sageShader.h"

#endif

#define BUF_LEN 128

class envInterface;
class graphicStreamer;
class gpuCompression;

#ifdef SAGE_AUDIO
class audioStreamer;
#endif

class sailConfig {
public:
	char  appName[SAGE_NAME_LEN];  // application name
	char  masterIP[SAGE_IP_LEN];  // the SAIL Master IP
	int   nwID;
	char  fsIP[SAGE_IP_LEN];
	int   fsPort;
	char 	bridgeIP[SAGE_IP_LEN];
	int 	bridgePort;
	bool	bridgeOn;
	int	syncPort;
	int	msgPort;
	int   nodeNum; // number of rendering nodes for an app instance
	int   appID;	// ID for each app instance
	int	blockX, blockY, blockSize;
	int	winX, winY, winWidth, winHeight; //window position and size on tiled display
	nwProtocol protocol;
	int	syncMode;
	int	streamMode;
	int	rcvBufSize;  // stream receiving buffer size
	
	int   rank;		// the rank of this node	
	int   resX;		// the width of application buffer in pixels
	int   resY;		// the height of application buffer in pixels
	sageRect   imageMap;  // the location of sub-image rendered by this node in the whole app image
	sagePixFmt pixFmt; // pixel format defined in sage.h 
	int   rowOrd;      // row order flag 
	bool  master;      // is master node or not
	bool  rendering;   // rendering or control only
	bool  asyncUpdate;
	sageCompressType compression;

       long totalFrames;

        bool audioOn;                           // audio on/off flag
        sageAudioMode audioMode;        // audio mode : capture, play, read, write
        int  audioPort;                         // audio port number
        int  audioDeviceNum;            // device number
        sageSampleFmt sampleFmt;        // audio sampling format : float, short, char, unsigned char
        long samplingRate;                      // audio sampling rate : default-44100
        int  channels;                          // number of audio channel
        int  framePerBuffer;            // audio frames per buffer
        sageSyncType syncType;
        char  audioFileName[BUF_LEN];  // application name
        int     audioBuffSize;

	char streamIP[SAGE_IP_LEN];
	int  frameRate;
	
	int bufWarnLimit, bufIncRatio, maxBlockLoss, ackInterval;
	int senderCheckInterval, minSendRate, maxSendRate;
	
	sailConfig();
	int init(char *fname); //initialize app configuration by config file
	int setAppName(char *name);
};	

class sail {
private:	
   	envInterface    *envIntf;
   	graphicStreamer *gStreamer;

	sailConfig	     config;
	sageNwConfig     nwCfg;
	bool             sailOn;
		
	int bufSize;
	float bytesPerPixel;
	int winID;
	
	std::deque<sageMessage> appMsgQueue;
	std::deque<char *> syncMsgQueue;
	
	int bufID;
	void *sailBuffer[2];
	sageBlock sailBlock[2];

	int blockNum;
	int sailFrameNum;
	int masterFrameNum;
	int syncPort;
	int waitNodes;
	int connectedNode;
	bool syncOn;
	bool pauseSync;
	bool connectionDone;
	
	int reconfigStep;
	//char *streamData;
	
	double reportTime;
	int oldFrame;
	float frameRate;
	float bandWidth;
	float totalBand;
	int perfWait;
	int reportRate;
	double frameInterval;

	GLuint sageFrameBuffer, sageRenderBuffer;	
	GLuint frameTex;
	GLenum pixelFormat;
	GLint  innerComponents;
	GLenum pixelDataType;
	gpuCompression *gpuObj;
	bool usingGPU;
	int fboBlockSize;
	
	sageSyncServer *syncServerObj;
	sageSyncClient *syncClientObj;	

	streamProtocol *nwObj;
	pthread_mutex_t	*bufferMutex;
	pthread_mutex_t	*blockMutex;
	pthread_mutex_t	*streamMutex;	
	pthread_mutex_t	*msgMutex;	
	pthread_cond_t		*notEmpty;
	pthread_cond_t		*notFull;
	int	queueLen;

	static void* msgThread(void *args);
	static void* nwThread(void *args);

	int checkSyncServer();
	int initPixelType(sagePixFmt pixelType);
	int generateSageBlocks();

        bool waitForSync;

#ifdef SAGE_AUDIO
        bool audioOn;                           // audio on/off flag
        int sailAudioFrameNum;
	audioStreamer        *aStreamer;
        int audiobufID;
        int usedbufID;
        void * audioAppRawBuffer[2];
        int audiobufSize[2];
        bool auioUpdated;
        int remainBufSize;
        void * remainBuf;
        sageAudioModule* audioObj;
        int bytesPerSample;
        sageAudioBlock sailAudioBlock;
        audioCircBuf* audioAppBuffer;
        static void* audioThread(void *args);
        static void* audioAppThread(void *args);
        int generateSageAudioBlocks(int buffSize);
        int getAppData();
#endif
	
public:
   sail();
   ~sail();

	int init(sailConfig &conf);
	int initNetworks(char *data);
	int readMessage();
	int sendMessage(sageMessage &msg);
	int sendMessage(int code);
	int sendMessage(int code, int data);
	int sendMessage(int code, char *data);
	int parseMessage(sageMessage &msg);	
	int swapBuffer(int mode = SAGE_BLOCKING);
	void* getBuffer();
	int initPixelBlocks();
	int streamPixelBlocks(int blockFrame);
	int streamFBO();

	//int resizeBuffer(int x, int y, int depth);
	int getRowOrder() { return config.rowOrd; }
	int getBufSize() { return bufSize; }
	int checkMsg(sageMessage &msg, bool blocking);
	int requestNewFrame();
	int shutdown();
	int sendPerformanceInfo();
	
	int initFrameBufferObject();  // initailize FBO of SAIL
	int bindFrameBufferObject();  // bind the FBO of SAIL
	int releaseFrameBufferObject();  // back to regular frame buffer
	int transferFBO();      // transfer pixels written into FBO to SAGE

#ifdef SAGE_AUDIO
	int initAudioStream(char *data);
	int pushData(int index, void *buf);
        int loadfile(char* filename, bool loop, long totalframes=0);
        int start();
        int stop();
        int pause();
        friend class audioStreamer;
#endif
		
	friend class graphicStreamer;
	friend class envInterface;

};

#endif
